/**
 * @fileoverview 一个简单js库

 * @Date: 11-11-4
 * @Time: 上午10:33
 * @author 2kid
 * @version 0.1
 */

(function () {

    var win = window, doc = window['document'];
    /**
     * @name F
     * @object
     * @namespace
     * 名称空间默认Fky，如果没有定义F，也可以用F。  <br>
     * Fky库的核心包括在Fky中的常用工具函数。  <br>
     * 所有核心函数都是通过F直接访问，而不是通过F.Core访问 <br>
     */
    var f = win['Fky'] = {};
    if (!win.F) {
        win['F'] = f;
    }
    /**
     * @name F.Core.version
     * @function
     * @namespace 返回版本信息，创建时间，修改时间等
     * @return {Object}
     */
    f.version = function () {
        return {
            ver:'RC 0.88',
            createtime:'Thu Nov 17 2011 10:22:47 GMT+0800',
            ModificationDate:'Thu Feb 16 2012 15:48:59 GMT+0800'
        }
    };
    /**
     * @name F.Core.config
     * @object
     * @namespace 配置一些选项
     * @version 0.1
     * @example
     *  选项：
     * {
     *      //是否打印错误
     *      debug:true,
     *      //当前文件目录
     *      curdir:''
     *  }
     */
    f.config = {
        debug:true,
        curdir:''
    };
    /**
     * @name F.Core.log
     * @namespace 用控制台或alert打印日志
     * @function
     */
    f.log = function () {
        if (!f.config.debug) {
            return;
        }
        var s;
        s = Array.prototype.join.call(arguments, ' ');
        window.console ? console.log(s) : alert(s);
    };
    /**
     * @name F.Core.type
     * @namespace 判断变量类型
     * @function
     * @version 0.3
     * @param o 需验证的变量
     * @param  {String} type  可选 可判断的类型 number,string,boolean,array,regexp,function,null,undefined,object
     * @return {Boolean | String}
     * @example
     * 例子：
     * 1.
     * var c=234;
     * if(f.type(c,'number')){
     *     alert('ok');
     * }
     * 2.
     * switch(f.type(c)){
     *    case 'number':{
     *
     *    }
     *    case 'string':{
     *
     *    }
     *
     * }
     */
    f.type = function (o, type) {
        var _t, curtype;
        curtype = ((_t = typeof(o)) == "object" ?
            o == null && "null" || Object.prototype.toString.call(o).slice(8, -1) :
            _t
            ).toLowerCase();
        if (type) {
            return type === curtype;
        } else {
            return curtype;
        }
    };
    /**
     * @name F.Core.ready
     * @namespace dom准备就绪
     * @function
     * @version  0.8
     * @param  {Function} fn(f) dom就绪时调用的函数、f为Fky
     * @example
     * 例子：
     * 1.
     * F.ready(function(f){
     *     f.log('ok');
     * });
     */
    f.ready = function () {
        var isReady = false,
            //函数列表
            readyList = [],
            //触发事件函数
            _fire;


        if ('addEventListener' in doc) {
            //w3c
            _fire = function () {
                doc.removeEventListener('DOMContentLoaded', _fire, false);
                _fireReady();
            };
            doc.addEventListener('DOMContentLoaded', _fire, false);
        } else {
            //  <= ie8
            _fire = function () {
                doc.detachEvent('onreadystatechange', _fire);
                if (doc.readyState == 'complete') {
                    _fireReady();
                }
            };
            doc.attachEvent('onreadystatechange', _fire);
            (function () {
                try {
                    //doScroll 如果抛出异常，说明dom未就绪
                    doc.documentElement.doScroll('left');
                    _fireReady();
                } catch (e) {
                    setTimeout(arguments.callee, 10);
                }
            })();

            //win.attachEvent('onload',_fireReady);
        }
        /**
         * 触发所有绑定函数
         */
        function _fireReady() {
            if (isReady) {
                return;
            }
            isReady = true;
            // 如果有绑定的函数
            if (readyList.length > 0) {
                //执行全部绑定的
                var fn, i = 0;
                while (fn = readyList[i++]) {
                    fn.call(win, f);
                }
                //重置
                readyList = [];
            }
        }

        return function (fn) {
            if (!f.type(fn, 'function')) {
                return false;
            }
            if (isReady) {
                // Execute the function immediately
                fn.call(win, f);
            } else {
                // Remember the function for later
                readyList.push(fn);
            }
        };
    }();
    /**
     * @name F.Core.each
     * @namespace 迭代数组或对象  默认执行环境window
     * @function
     * @version 0.5
     * @param {Array | Object} o 可迭代的对象或数组
     * @param {Function} fn(item,i,o)
     * @param {Object} ctx 可选 执行环境
     * @example
     * 例子：
     * 1.
     * F.each(['a','b','c'],function(item,i,arr){
     *     f.log(item,i,arr);
     *     //输出
     *     // a,0,['a','b','c']
     *     // b,1,['a','b','c']
     *     // c,2,['a','b','c']
     * });
     * 2.
     * F.each({a:234,b:23},function(val,key){
     *    f.log(val,key);
     *    //输出
     *    //  234,a
     *    //  23,b
     * });
     * 3.
     * var c=function(){}
     * F.each(['a','b','c'],function(){
     *     f.log(this);
     *     //this==c;
     * },c)；
     *
     */
    f.each = function (o, fn, ctx) {
        var i = 0,
            length = o.length;
        //
        ctx = ctx || win;
        if ((f.type(o, 'function') || f.type(o, 'object')) && !o.item && !o.callee && !o.nodeName) {
            for (var key in o) {
                fn.call(ctx, o[key], key, o);
            }
        } else {
            //arguments,collection,elements,array的迭代
            for (; i < length; i++) {
                fn.call(ctx, o[i], i, o);
            }
        }


    };
    /**
     * @name F.Core.extend
     * @namespace  使用原型实现继承，子类调用父类构造函数 sub.superclass.call(this,arg)
     * @function
     * @version 0.1
     * @param {Function} sup 超类
     * @param {Function | Object} sub Function为子类 | Object 覆盖/扩展sup原型的方法或属性
     * @param {Object | Boolean} o Object子类覆盖/扩展的方法或属性 | Boolean同第4个参数
     * @p {Boolean} true时，添加的属性/方法扩展到对象上，false时，添加的属性/方法扩展到原型上
     * @example
     * 例子：
     * 1.
     * function Person(sex){
     *     this.sex=sex;
     * }
     * Person.prototype.eat=function(){
     *     alert('吃了');
     * }
     *
     * function Boy(){
     *      //调用父类构造函数
     *      Boy.superclass.call(this,'男的');
     * }
     * //继承Person，并在原型上扩展
     * f.extend(Person,Boy,{
           xiaban:function(){
               alert('下班了');
           }
      });
     //直接在Boy上扩展、
     f.extend(Boy,{
          chifan:function(){
              alert('吃饭了');
          }
     },true);

     alert(new Boy().sex);//弹出男的

     new Boy().xiaban();
     Boy.chifan();
     *
     *
     */
    f.extend = function (sup, sub, o, p) {
        //
        if (!f.type(sup, 'function')) {
            f.log('f.extend error');
            return;
        }
        p = p || o || false;
        if (f.type(sub, 'object')) {
            if (p !== true) {
                f.each(sub, function (v, k) {
                    sup.prototype[k] = v;
                });
            } else {
                f.each(sub, function (v, k) {
                    sup[k] = v;
                });
            }
            return;
        }

        //拷贝原型
        sub.prototype = sup.prototype;
        //添加constructor属性，之前被覆盖
        sub.prototype.constructor = sub;
        //添加父类的引用
        sub.superclass = sup;
        if (f.type(o, 'object')) {
            //添加属性或方法
            if (p !== true) {
                f.each(o, function (v, k) {
                    sub.prototype[k] = v;
                });
            } else {
                f.each(o, function (v, k) {
                    sub[k] = v;
                });
            }
        }
    };
    /**
     * @name F.Core.merge
     * @namespace  合并数组或{}，如果第一个参数为数组，则返回数组，后面的数组或对象或直接push到第一个数组，不会替换、
     *  如果要替换，第一个参数为{}，则会替换
     *  第一个参数设置为ture。如果第一个参数为true，会执行深度拷贝。
     * @function
     * @version 0.1
     * @param arg1
     * @param arg2
     * @param arg3
     * @param ...
     * @return {Array | Object }
     * @example
     * 例子：
     * 1.
     *  var c=[2,3,4];
     *  var d=[2,5];
     *  var e=f.merge(c,d);
     *  //e=[2,3,4,2,5];
     *  2.
     *  var c=[2,3,4];
     *  var d={0:2,:4};
     *  var e=f.merge(c,d);
     *  //e=[2,3,4,2,4];
     *  3.
     *  var c={0:3,1:5};
     *  var d={1:7,2:9};
     *  var e=f.merge(c,d);
     *  //e={0:3,1:7,2:9};
     *  4.
     *  var c={0:3,2:{2:1,4:5}};
     *  var d={0:7,2:{2:3,6:6}};
     *  var e=f.merge(true,c,d);
     *  var e=f.merge(c,d);
     *  //e={0:7,2:{2:3,:6:6};
     *  var e=f.merge(true,c,d);
     *  //e={0:7,2:{2:3,4:5,:6:6};
     */
    f.merge = function () {
        var result = {},
            i = 0,
            length = arguments.length;
        arg = arguments,
            arg0 = arg[0],
            deep = false,
            arr = false;
        //如果第一个参数为true ，循环从第二个参数开始
        if (arg0 === true) {
            deep = true;
            arg0 = arg[1];
            i = 1;
        }
        //如果第一个参数为数组，使返回的结果为数组，否则为object
        if (f.type(arg0, 'array')) {
            arr = true;
            result = [];
        }

        for (; i < length; i++) {
            _copy(arg[i], result);
        }
        function _copy(obj, r) {
            f.each(obj, function (o, k) {
                //去掉item和length属性
                if (k === 'item' || k === 'length') return;
                //如果第一个参数是数组
                if (arr && !deep) {
                    r.push(o);
                } else {
                    //如果是深度拷贝
                    if (deep) {
                        //如果是数组
                        if (f.type(o, 'array')) {
                            r[k] = _copy(o, r[k] || []);
                        } else if (f.type(o, 'object')) {
                            //如果是对象
                            r[k] = _copy(o, r[k] || {});
                        } else {
                            r[k] = o;
                        }

                    } else {
                        r[k] = o;
                    }
                }
            });
            return r;
        }

        return result;
    };
    /**
     * @name F.Core.inarray
     * @namespace 检索元素是否在数组中，存在则返回数组的索引，否则返回-1
     * @function
     * @version 0.1
     * @param {Array} array
     * @param  elem
     * @return {Number}
     * @example
     * 例子：
     * 1.
     * if(f.inarray([2,4],3)>-1){
     *      alert('in');
     * }
     *
     */
    f.inarray = function (array, elem) {
        if (array.indexOf) {
            return array.indexOf(elem);
        }
        for (var i = 0, length = array.length; i < length; i++) {
            if (array[ i ] === elem) {
                return i;
            }
        }
        return -1;
    };
    /**
     * @name F.Core.filter
     * @namespace  过滤数组或对象，根据fn的返回值，默认环境window
     * @function
     * @version 0.1
     * @param o
     * @param fn(item,i,o)
     * @param ctx
     * @return {Object| Array}
     * @example
     * 例子：
     * 1.
     * var c=f.filter([1,2,3,4],function(val){
     *     return val%2===0;
     * });
     * //c=[2, 4];
     *
     */
    f.filter = function (o, fn, ctx) {
        var newo = [];
        ctx = ctx || win;
        if ('filter' in o) {
            newo = o.filter(fn, ctx);
        } else if (f.type(o, 'object') && !o.item && !o.callee && !o.nodeName) {
            newo = {};
            f.each(o, function (v, i, o) {
                if (fn.call(ctx, v, i, o)) {
                    newo[i] = v;
                }
            });
        } else {
            f.each(o, function (v, i, o) {
                if (fn.call(ctx, v, i, o)) {
                    newo.push(v);
                }
            });
        }
        return newo;
    };
    /**
     * @name F.Core.trim
     * @namespace  去掉字符串首尾空格，换行等
     * @function
     * @version 0.1
     * @param {String} str
     * @return {String}
     * @example
     * 例子：
     * var c=" sdf \n";
     * c=f.trim(c);
     * //c=sdf;
     */
    f.trim = function (str) {
        var s = '', retrim = /^\s+|\s+$/g;
        if (!f.type(str, 'string')) {
            f.log('f.trim  arg error!');
            return s;
        }
        if (str.trim) {
            s = str.trim();
        } else {
            s = str.replace(retrim, '');
        }
        return s;
    };
    /**
     * @name F.Core.load
     * @namespace 加载js，css文件
     * @function
     * @param {Array} srcarr 文件路径 ['sdf.js','sdf.css']
     * @param {Function|Array} fn(src) 调用函数，如果是一个函数，则成功加载完成所有的文件后调用fn，
     *                                      如果是一个数组，则每加载一个文件，调用对应的fn，若没有fn，可以写 null
     *                                      如： [fn1,fn2,null,fn4]
     *
     * @param {String} charset 文件编码
     * @param {Object} ctx 执行环境
     * @example
     * 例子：
     * 1.
     * f.load(['aa.js','aa.css'],function(){
     *    alert('aa.js,aa.css 都加载成功了');
     * });
     * 2.
     * f.load(['aa.js','aa.css'],[function(){
     *     alert('aa.js加载成功了');
     * },function(){
     *     alert('aa.css加载成功了');
     * });
     *
     */
    f.load = function () {
        var
            //上一个是否成功
            last = true;

        function styleOnload(node, callback) {
            // for IE6-9 and Opera
            if (node.attachEvent) {
                node.attachEvent('onload', callback);
            }
            // // polling for Firefox, Chrome, Safari
            else {
                setTimeout(function () {
                    poll(node, callback);
                }, 0); // for cache
            }
        }

        function poll(node, callback) {
            if (callback.isCalled) {
                return;
            }

            var isLoaded = false;

            if (/webkit/i.test(navigator.userAgent)) {//webkit
                if (node['sheet']) {
                    isLoaded = true;
                }
            }
            // for Firefox
            else if (node['sheet']) {
                try {
                    if (node['sheet'].cssRules) {
                        isLoaded = true;
                    }
                } catch (ex) {
                    // NS_ERROR_DOM_SECURITY_ERR
                    if (ex.code === 1000) {
                        isLoaded = true;
                    }
                }
            }

            if (isLoaded) {
                // give time to render.
                setTimeout(function () {
                    callback();
                }, 1);
            }
            else {
                setTimeout(function () {
                    poll(node, callback);
                }, 1);
            }
        }

        function run(sr, charset, fn) {
            if (!sr) return;
            var JS = /\.js(\?.*)?$/i,
                CSS = /\.css(\?.*)?$/i,
                head = document.head || document.getElementsByTagName('head')[0],
                o;
            if (CSS.test(sr)) {
                //    <link rel="stylesheet" href="">
                o = document.createElement('link');
                o.type = 'text/css';
                o.rel = 'stylesheet';
                o.href = sr;
                styleOnload(o, fn);


            } else
            //if(JS.test(sr))
            {
                //    <script type="text/javascript" charset="utf-8" src=""></script>
                o = document.createElement('script');
                o.type = 'text/javascript';
                o.charset = charset || 'utf-8';
                o.async = 'true';
                o.src = sr;
                o.onload = o.onreadystatechange = function () {
                    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {

                        if (fn) {

                            fn();
                        }

                        o.onload = o.onreadystatechange = null;
                    }
                };

            }


            o.onerror = function () {
                f.log('file type error:', sr);
                o.onerror = null;
            };
            win.onerror = function () {
                win.onerror = null;
                last = false;
            };

            head.appendChild(o);
        }

        return function (srcarr, fn, charset, ctx) {
            var ctx = ctx || win;
            //开始加载第一个
            var src = srcarr.shift();
            run(src, charset, function () {

                if (f.type(fn, 'array')) {
                    f.type(fn.shift(), 'function') ? fn.shift().call(ctx, src) : 0;
                } else if (srcarr.length === 0 && fn) {
                    fn.call(ctx, src);
                }


                run(srcarr.shift(), charset, arguments.callee);

            });

        }
    }();

    (function () {

        var REQUIRES = 'requires',
            //模块名称路径
            modreg = {},
            FN = 'fn';
        /**
         * @name F.Core.reg
         * @namespace 注册模块
         * @function
         * @param modname  模块名称
         * @param fn(f,mod,..)  模块调用函数，返回模块
         * @param param 目前参数为：{ requires:　[　 'dom/select'　 ]　 },需要的模块路径、js文件可不带.js后缀名
         * @example
         * 例子：
         * 1.
         * //注册drag模块
         * //在f.js同目录建立drag.js
         * //drag.js内容：
         * F.reg('drag',function(f,drag){
         *      return drag;
         *  },{
         *      requires:[
         *          'drag/base'
         *      ]
         * });
         * //再建立drag目录，在drag目录建立base文件(base.js文件是必须的)。
         * //base.js内容：
         * F.reg('drag/base',function(f,dom,event){
         *       var dragdrop ={};
         *       dragdrop...
         *
         *       return dragdrop;
         * },{
         *    requires:[
         *        'dom',
         *        'event'
         *    ]
         *  });
         *
         * });
         */
        f.reg = function (modname, fn, param) {
            //  if(! modreg[modname] ){
            modreg[modname] = {};
            modreg[modname][FN] = fn;
            modreg[modname][REQUIRES] = param ? param[REQUIRES] || [] : [];
            //    }

        };
        /**
         * @name F.Core.use
         * @namespace 使用模块
         * @function
         * @param mod 模块名称
         * @param fn(f,m,...) 模块加载完成调用的函数
         * @param ctx 调用函数执行环境
         * @example
         * 例子：
         * 1.
         * //使用drag模块
         *  f.use('drag',function(f,drag){
         *        drag.enable('drag');
         *        drag.add('dragstart',function(e){
         *          console.log(e.startOffset)
         *
         *       });
         *    });
         */
        f.use = function (mod, fn) {
            var loadqueue = mod.split(',');
            //调用的函数队列
            var fnqueue = [] ,
                rightname;
            //加载队列的最后一个。
            loadmod(loadqueue.pop(), function (m) {
                //event event/handle
                var nextmod;
                if (f.type(m, 'undefined')) {

                    nextmod = loadqueue.shift();

                    if (!f.type(nextmod, 'undefined')) {
                        loadmod(nextmod, arguments.callee);
                    }
                } else {
                    //modreg['dom']={}
                    // modreg['dom'][FN]
                    // modreg['dom'][REQUIRES]
                    // dom
                    //把需要调用的函数放入队列
                    fnqueue.push({
                        fn:modreg[m][FN],
                        modname:m,
                        requires:modreg[m][REQUIRES]
                    });


                    //把需要加载的放入队列
                    loadqueue = f.merge(loadqueue, modreg[m][REQUIRES]);

                }


                //
                if (loadqueue.length === 0) {

                    (function () {
                        //执行加载完成的函数

                        for (var i = fnqueue.length - 1; i >= 0; i--) {
                            //获取正确的模块名称
                            rightname = rightmod(fnqueue[i]['modname']);
                            //把requires的模块加入参数

                            //调用函数
                            f[rightname] = fnqueue[i]['fn'].apply(win, makearg(fnqueue[i]['requires'], rightname, isBase(fnqueue[i]['modname'])));

                        }
                        fn.apply(win, makearg(mod.split(',')));

                    })();


                } else {

                    loadmod(loadqueue.pop(), arguments.callee);
                }

            });


            function loadmod(m, callfn) {
                var tmpsrc = suitedsrc([m]);
                //如果已经注册，说明已经加载，直接添加到队列
                //event.js
                if (modreg[m]) {
                    callfn(m);
                    return;
                }

                //['event.js',fn] event/handle
                if (!isCss(tmpsrc)) {
                    f.load(tmpsrc, function () {
                        callfn(m);
                    });

                } else {
                    f.load(tmpsrc, function () {

                        callfn();
                    });
                }

            }


        };

        function makearg(arg, curmod, isbase) {

            var fnarg = [f];
            // use fn 的参数
            if (!isbase && curmod && f[curmod]) {
                fnarg.push(f[curmod]);
            }
            //arg = [   'dom',  'event' ]
            f.each(arg, function (ag) {

                //是 模块 dom ?
                if (isMod(ag)) {

                    ag = rightmod(ag);

                    f[ag] ? fnarg.push(f[ag]) : 0;
                }

            });
            //  console.log(arg,curmod,fnarg)
            return fnarg;
        }

        function isBase(mod) {
            return mod.indexOf('/base') > -1;
        }

        function isMod(mod) {
            return mod.indexOf('/') === -1;
        }

        function isCss(m) {
            if (f.type(m, 'array')) {
                m = m.join('');
            }
            return m.toLowerCase().indexOf('.css') > -1;
        }

        //返回正确的模块名称，dom/attr => Dom, dom=>Dom
        function rightmod(m) {
            var s,
                sh = m.indexOf('/') > -1 ? m.indexOf('/') : m.length;
            s = m.slice(1, sh);
            s = m.slice(0, 1).toUpperCase() + s;


            return s;

        }

        /**
         * 返回合适的路径
         * @param {Array} par   [dom,dom/as,dom/ds.css]
         * @return {Array}
         */
        function suitedsrc(par) {

            if (!f.type(par, 'array')) {
                return false;
            }
            f.each(par, function (p, i) {
                //如 dom/attr，返回 dom/attr.js
                if (!isCss(p)) {
                    par[i] = p + '.js';
                }
                par[i]=f.config.curdir+par[i];
            });

            return par;
        }

    })();


})();

